package com.didiglobal.thriftmock.server;

import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.thrift.TBase;
import org.apache.thrift.TFieldRequirementType;
import org.apache.thrift.meta_data.FieldMetaData;
import org.apache.thrift.meta_data.FieldValueMetaData;
import org.apache.thrift.protocol.TStruct;
import org.apache.thrift.protocol.TTupleProtocol;
import org.apache.thrift.protocol.TType;
import org.apache.thrift.scheme.IScheme;
import org.apache.thrift.scheme.SchemeFactory;
import org.apache.thrift.scheme.StandardScheme;
import org.apache.thrift.scheme.TupleScheme;

import java.util.BitSet;
import java.util.Collections;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;

/**
 * The origin source of this class is generated by thrift command with a thrift file,
 * I modified the code to make it work without dependency on any specified thrift service.
 */
public class MockResult implements TBase<MockResult, MockResult._Fields>, java.io.Serializable, Cloneable, Comparable<MockResult>   {

  private static final String SUCCESS_NAME = "success";
  private static final org.apache.thrift.protocol.TField SUCCESS_FIELD_DESC = new org.apache.thrift.protocol.TField(SUCCESS_NAME, TType.STRUCT, (short)0);

  public final String methodName;
  public final TStruct structDesc;
  public final Map<_Fields, FieldMetaData> metaDataMap;
  public final Map<Class<? extends IScheme>, SchemeFactory> schemes = new HashMap<>();

  private TBase success;

  public MockResult(String methodName, TBase value) {
    this.methodName = methodName;
    this.success = value;
    this.structDesc = new TStruct(methodName+"_result");

    //init metaDatMap
    Map<_Fields, FieldMetaData> tmpMap = new EnumMap<>(_Fields.class);
    tmpMap.put(_Fields.SUCCESS,
               new FieldMetaData(SUCCESS_NAME, TFieldRequirementType.DEFAULT,
                                 new FieldValueMetaData(TType.STRUCT          , value.getClass().getCanonicalName())));
    metaDataMap = Collections.unmodifiableMap(tmpMap);
    FieldMetaData.addStructMetaDataMap(MockResult.class, metaDataMap);

    schemes.put(StandardScheme.class, new MockResultStandardSchemeFactory(structDesc));
    schemes.put(TupleScheme.class, new MockResultTupleSchemeFactory());

  }

  public MockResult(MockResult mockResult) {
    this(mockResult.methodName, mockResult.success);
  }

    /** The set of fields this struct contains, along with convenience methods for finding and manipulating them. */
    public enum _Fields implements org.apache.thrift.TFieldIdEnum {
      SUCCESS((short)0, SUCCESS_NAME);

      private static final Map<String, _Fields> byName = new HashMap<>();

      static {
        for (_Fields field : EnumSet.allOf(_Fields.class)) {
          byName.put(field.getFieldName(), field);
        }
      }

      private final short thriftId;
      private final String fieldName;

      _Fields(short thriftId, String fieldName) {
        this.thriftId = thriftId;
        this.fieldName = fieldName;
      }

      /**
       * Find the _Fields constant that matches fieldId, or null if its not found.
       */
      public static _Fields findByThriftId(int fieldId) {
        return fieldId == 0 ? SUCCESS : null;
      }

      /**
       * Find the _Fields constant that matches fieldId, throwing an exception
       * if it is not found.
       */
      public static _Fields findByThriftIdOrThrow(int fieldId) {
        _Fields fields = findByThriftId(fieldId);
        if (fields == null) {
          throw new IllegalArgumentException("Field " + fieldId + " doesn't exist!");
        }
        return fields;
      }

      /**
       * Find the _Fields constant that matches name, or null if its not found.
       */
      public static _Fields findByName(String name) {
        return byName.get(name);
      }



      public short getThriftFieldId() {
        return thriftId;
      }

      public String getFieldName() {
        return fieldName;
      }
    }

    /**
     * Performs a deep copy on <i>other</i>.
     */
    /**
    public MockResult(MockResult other) {
      if (other.isSetSuccess()) {
        this.success = other.success;
      }
    }
     **/


    //face deep copy
    public MockResult deepCopy() {
      return this;
    }

    @Override
    public void clear() {
      this.success = null;
    }

    public TBase getSuccess() {
      return this.success;
    }

    public MockResult setSuccess(TBase success) {
      this.success = success;
      return this;
    }

    public void unsetSuccess() {
      this.success = null;
    }

    /** Returns true if field success is set (has been assigned a value) and false otherwise */
    public boolean isSetSuccess() {
      return this.success != null;
    }

    public void setSuccessIsSet(boolean value) {
      if (!value) {
        this.success = null;
      }
    }

    public void setFieldValue(_Fields field, Object value) {
      if (field == _Fields.SUCCESS) {
        if (value == null) {
          unsetSuccess();
        } else {
          setSuccess((TBase) value);
        }
      }
    }

    public Object getFieldValue(_Fields field) {
      if (field == _Fields.SUCCESS) {
        return getSuccess();
      }
      throw new IllegalStateException();
    }

    /** Returns true if field corresponding to fieldID is set (has been assigned a value) and false otherwise */
    public boolean isSet(_Fields field) {
      if (field == null) {
        throw new IllegalArgumentException();
      }
      if (field != _Fields.SUCCESS) {
        throw new IllegalStateException();
      }
      return isSetSuccess();
    }

    @Override
    public boolean equals(Object that) {
      if (that == null)
        return false;
      if (that instanceof MockResult)
        return this.equals((MockResult)that);
      return false;
    }

    public boolean equals(MockResult that) {
      if (that == null) {
        return false;
      }

      boolean thisPresentSuccess = this.isSetSuccess();
      boolean thatPresentSuccess = that.isSetSuccess();
      if (thisPresentSuccess || thatPresentSuccess) {
        if (!(thisPresentSuccess && thatPresentSuccess))
          return false;
        if (!this.success.equals(that.success))
          return false;
      }

      return true;
    }

    @Override
    public int hashCode() {
      HashCodeBuilder builder = new HashCodeBuilder();

      boolean presentSuccess = isSetSuccess();
      builder.append(presentSuccess);
      if (presentSuccess)
        builder.append(success);

      return builder.toHashCode();
    }

    @Override
    public int compareTo(MockResult other) {
      if (!getClass().equals(other.getClass())) {
        return getClass().getName().compareTo(other.getClass().getName());
      }

      int lastComparison = 0;

      lastComparison = Boolean.valueOf(isSetSuccess()).compareTo(other.isSetSuccess());
      if (lastComparison != 0) {
        return lastComparison;
      }
      if (isSetSuccess()) {
        lastComparison = org.apache.thrift.TBaseHelper.compareTo(this.success, other.success);
        if (lastComparison != 0) {
          return lastComparison;
        }
      }
      return 0;
    }

  public _Fields fieldForId(int fieldId) {
      return _Fields.findByThriftId(fieldId);
    }

    public void read(org.apache.thrift.protocol.TProtocol iprot) throws org.apache.thrift.TException {
      schemes.get(iprot.getScheme()).getScheme().read(iprot, this);
    }

    public void write(org.apache.thrift.protocol.TProtocol oprot) throws org.apache.thrift.TException {
      schemes.get(oprot.getScheme()).getScheme().write(oprot, this);
    }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder("MockResult(");
      sb.append("success:");
      if (this.success == null) {
        sb.append("null");
      } else {
        sb.append(this.success);
      }
      sb.append(")");
      return sb.toString();
    }

    public void validate() throws org.apache.thrift.TException {
      // check for required fields
      // check for sub-struct validity
    }

    private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
      try {
        write(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(out)));
      } catch (org.apache.thrift.TException te) {
        throw new java.io.IOException(te);
      }
    }

    private void readObject(java.io.ObjectInputStream in) throws java.io.IOException, ClassNotFoundException {
      try {
        read(new org.apache.thrift.protocol.TCompactProtocol(new org.apache.thrift.transport.TIOStreamTransport(in)));
      } catch (org.apache.thrift.TException te) {
        throw new java.io.IOException(te);
      }
    }

    private static class MockResultStandardSchemeFactory implements SchemeFactory {
      private TStruct desc;
      public MockResultStandardSchemeFactory(TStruct desc) {
        this.desc = desc;
      }
      public MockResultStandardScheme getScheme() {
        return new MockResultStandardScheme(desc);
      }
    }

    private static class MockResultStandardScheme extends StandardScheme<MockResult> {
      private TStruct desc;
      public MockResultStandardScheme(TStruct desc) {
        this.desc = desc;
      }

      public void read(org.apache.thrift.protocol.TProtocol iprot, MockResult struct) throws org.apache.thrift.TException {
        org.apache.thrift.protocol.TField schemeField;
        iprot.readStructBegin();
        while (true) {
          schemeField = iprot.readFieldBegin();
          if (schemeField.type == TType.STOP) {
            break;
          }
          processSchemeField(schemeField, iprot, struct);
          iprot.readFieldEnd();
        }
        iprot.readStructEnd();

        // check for required fields of primitive type, which can't be checked in the validate method
        struct.validate();
      }

      private void processSchemeField(org.apache.thrift.protocol.TField schemeField,
                                     org.apache.thrift.protocol.TProtocol iprot,
                                     MockResult struct) throws org.apache.thrift.TException {
        if (schemeField.id == SUCCESS_FIELD_DESC.id) {
          readSuccessStruct(schemeField, iprot, struct);
        } else {
          org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
        }
      }

      private void readSuccessStruct(org.apache.thrift.protocol.TField schemeField,
                                     org.apache.thrift.protocol.TProtocol iprot,
                                     MockResult struct) throws org.apache.thrift.TException {
        if (schemeField.type == TType.STRUCT) {
          try {
            struct.success = struct.success.getClass().newInstance();
          } catch (Exception e) {
            throw new IllegalArgumentException("init object failed:" + struct.success.getClass() + e);
          }
          struct.success.read(iprot);
          struct.setSuccessIsSet(true);
        } else {
          org.apache.thrift.protocol.TProtocolUtil.skip(iprot, schemeField.type);
        }
      }

      public void write(org.apache.thrift.protocol.TProtocol oprot, MockResult struct) throws org.apache.thrift.TException {
        struct.validate();

        oprot.writeStructBegin(desc);
        if (struct.success != null) {
          oprot.writeFieldBegin(SUCCESS_FIELD_DESC);
          struct.success.write(oprot);
          oprot.writeFieldEnd();
        }
        oprot.writeFieldStop();
        oprot.writeStructEnd();
      }

    }

    private static class MockResultTupleSchemeFactory implements SchemeFactory {
      public MockResultTupleScheme getScheme() {
        return new MockResultTupleScheme();
      }
    }

    private static class MockResultTupleScheme extends TupleScheme<MockResult> {

      @Override
      public void write(org.apache.thrift.protocol.TProtocol prot, MockResult struct) throws org.apache.thrift.TException {
        TTupleProtocol oprot = (TTupleProtocol) prot;
        BitSet optionals = new BitSet();
        if (struct.isSetSuccess()) {
          optionals.set(0);
        }
        oprot.writeBitSet(optionals, 1);
        if (struct.isSetSuccess()) {
          struct.success.write(oprot);
        }
      }

      @Override
      public void read(org.apache.thrift.protocol.TProtocol prot, MockResult struct) throws org.apache.thrift.TException {
        TTupleProtocol iprot = (TTupleProtocol) prot;
        BitSet incoming = iprot.readBitSet(1);
        if (incoming.get(0)) {
          try {
            struct.success = struct.success.getClass().newInstance();
          } catch (Exception e) {
            throw new IllegalArgumentException("init object failed:" + struct.success.getClass() + e);
          }
          struct.success.read(iprot);
          struct.setSuccessIsSet(true);
        }
      }
    }

  }


